class Calendar {
  constructor() {
    this.currentDate = new Date();
    this.today = new Date();
    this.today.setHours(0, 0, 0, 0);
    this.selectedDate = this.today;
    this.touchStartY = 0;
    this.touchEndY = 0;
    this.isAnimating = false;
  }
  /**
   * 初始化日历
   */
  initCalendar(startDate) {
    const months = this.monthDiff(startDate, new Date());
    // 初始化DOM元素
    this.calendarHeader = document.getElementById('calendar-header');
    this.calendarBody = document.getElementById('calendar-body');
    this.loadingElement = this.calendarBody.querySelector('.loading');
    this.monthContainers = [];
    for (let i = 0; i < months; i++) {
      const container = document.createElement('div');
      container.className = 'month-container';
      this.calendarBody.appendChild(container);
      this.monthContainers.push(container);
    }
    // 初始加载
    this.loadInitialMonths();
    this.addEventListeners();
  }
  /**
   * 两个日期中间的月差
   * @param {*} d1
   * @param {*} d2
   * @returns 
   */
  monthDiff(d1, d2) {
    let months;
    months = (d2.getFullYear() - d1.getFullYear()) * 12;
    months -= d1.getMonth();
    months++
    months += d2.getMonth();
    return months <= 0 ? 0 : months;
  }
  loadInitialMonths () {
    // 显示加载状态
    this.loadingElement.style.display = 'block';
    // 加载 截止到目前这个月
    const promiseMonths = this.monthContainers.map((item, index) => {
      const i = -this.monthContainers.length + index + 1;
      return this.loadMonthData(i, index)
    })
    Promise.all(promiseMonths).then(() => {
      this.loadingElement.style.display = 'none';
      this.navTo();
      this.renderMonthColor();
    });
  }
  loadMonthData (offset, index) {
    return new Promise((resolve) => {
      const date = new Date(this.currentDate);
      date.setMonth(date.getMonth() + offset);
      setTimeout(() => {
        this.renderMonth(date, this.monthContainers[index]);
        resolve();
      }, 100);
    });
  }
  navTo(date) {
    let finalDate = this.currentDate;
    if (date) {
      finalDate = date;
    }
    const year = finalDate.getFullYear();
    const month = finalDate.getMonth() + 1;
    const navDom = document.getElementById(`${year}-${month}`);
    navDom.scrollIntoView()
    this.updateHeader(`${year}-${month}`);
  }
  updateHeader (id) {
    let date = this.currentDate;
    if (id) {
      const year = id.split('-')[0];
      const month = id.split('-')[1];
      date.setFullYear(year);
      date.setMonth(month - 1);
    }
    const options = { year: 'numeric', month: 'long' };
    this.calendarHeader.textContent = date.toLocaleDateString('zh-CN', options);
  }

  renderMonth (date, container) {
    const year = date.getFullYear();
    const month = date.getMonth();
    const isCurrentMonth = year === this.currentDate.getFullYear() && month === this.currentDate.getMonth();
    container.id = `${year}-${month + 1}`
    // 清空容器
    container.innerHTML = '';

    // 创建日期网格
    const daysContainer = document.createElement('div');
    daysContainer.className = 'days';
    container.appendChild(daysContainer);

    // 获取当月第一天
    const firstDay = new Date(year, month, 1);
    // 获取当月第一天是星期几（0-6，0是星期日）
    const firstDayOfWeek = firstDay.getDay();
    // 获取当月天数
    const daysInMonth = new Date(year, month + 1, 0).getDate();
    // 获取上个月的天数
    const daysInLastMonth = new Date(year, month, 0).getDate();

    // 添加上个月的几天（如果有）
    for (let i = firstDayOfWeek - 1; i >= 0; i--) {
      const day = daysInLastMonth - i;
      const dayElement = this.createBlankDay();
      daysContainer.appendChild(dayElement);
    }

    // 添加当月的天数
    for (let i = 1; i <= daysInMonth; i++) {
      const dayElement = this.createDayElement(i, year, month);

      // 检查是否是今天
      if (year === this.today.getFullYear() &&
        month === this.today.getMonth() &&
        i === this.today.getDate()) {
        dayElement.classList.add('today');
      }

      // 检查是否是选中日期
      if (this.selectedDate &&
        year === this.selectedDate.getFullYear() &&
        month === this.selectedDate.getMonth() &&
        i === this.selectedDate.getDate()) {
        dayElement.classList.add('selected');
      }

      daysContainer.appendChild(dayElement);
    }

    // 添加下个月的几天（如果有）
    const totalCells = Math.ceil((firstDayOfWeek + daysInMonth) / 7) * 7;
    const nextMonthDays = totalCells - (firstDayOfWeek + daysInMonth);
    for (let i = 1; i <= nextMonthDays; i++) {
      const dayElement = this.createBlankDay();
      daysContainer.appendChild(dayElement);
    }
  }
  /**
   * 创建空白日
   */
  createBlankDay() {
    const blankDayElement = document.createElement('div');
    blankDayElement.className = 'blank-day';
    return blankDayElement;
  }
  /**
   * 创建日
   * @param {*} day 
   * @param {*} year 
   * @param {*} month 
   * @returns 
   */
  createDayElement (day, year, month) {
    const dayElement = document.createElement('div');
    dayElement.className = 'day';
    dayElement.textContent = day;
    dayElement.dataset.date = `${year}-${month + 1}-${day}`;

    // 添加点击事件
    dayElement.addEventListener('click', () => {
      const date = new Date(year, month, day);
      // 设置选中日期
      this.selectedDate = date;
      this.renderDay();
      // 待完善 点击日历，外部时间轴跳转
      // if (dayElement.classList.contains('has-events')) {
      //   const date = dayElement.dataset.date;
      // }
    })
    return dayElement;
  }
  renderMonthColor() {
    const yM = this.calendarHeader.textContent.match(/\d+/g);
    const year = yM[0];
    const month = yM[1];
    document.querySelectorAll('.month-container').forEach(item => {
      item.classList.remove('choose-month');
      const [y, m] = item.id.split('-')
      if (year === y && month === m) {
        item.classList.add('choose-month');
      }
    }) 
  }
  /**
   * 渲染 每天 dom
   */
  renderDay() {
    document.querySelectorAll('.day').forEach(item => {
      // 刷新事件
      const hasDate = calendarEvents.find(item1 => {
        const [
          year,
          month,
          day
        ] = item1.date.split('-')
        const pMonth = Number(month);
        const pDay = Number(day);
        return `${year}-${pMonth}-${pDay}` === item.dataset.date
      });
      if (hasDate) {
        item.classList.add('has-events')
      }
      // 刷新选中日期
      item.classList.remove('selected')
      const [year, month, day] = item.dataset.date.split('-')
      const isSelected = (Number(year) === this.selectedDate.getFullYear()) &&
      (Number(month - 1) === this.selectedDate.getMonth()) &&
      (Number(day) === this.selectedDate.getDate())      
      if (isSelected) {
        item.classList.add('selected');
      }
    })
  }

  addEventListeners () {
    function throttleRAF(func) {
      let ticking = false;
      return function() {
        const context = this;
        const args = arguments;
        if (!ticking) {
          window.requestAnimationFrame(function() {
            func.apply(context, args);
            ticking = false;
          });
          ticking = true;
        }
      };
    }
    function findLargestVisibleElement(parentElement, returnArea = false) {
      const children = Array.from(parentElement.children);
      const parentRect = parentElement.getBoundingClientRect();
      let largestElement = null;
      let maxArea = 0;
      children.forEach(child => {
        const childRect = child.getBoundingClientRect();
        // 计算子元素在父元素可视区域内的可见部分
        const visibleLeft = Math.max(childRect.left, parentRect.left);
        const visibleTop = Math.max(childRect.top, parentRect.top);
        const visibleRight = Math.min(childRect.right, parentRect.right);
        const visibleBottom = Math.min(childRect.bottom, parentRect.bottom);
        // 计算可见区域的宽高
        const visibleWidth = Math.max(0, visibleRight - visibleLeft);
        const visibleHeight = Math.max(0, visibleBottom - visibleTop);
        const visibleArea = visibleWidth * visibleHeight;
        // 更新最大面积元素
        if (visibleArea > maxArea) {
          maxArea = visibleArea;
          largestElement = child;
        }
      });
      return returnArea ? { element: largestElement, area: maxArea } : largestElement;
    }
    
    // 使用示例
    const container = document.getElementById('calendar-body');
    container.addEventListener('scroll', throttleRAF(() => {
      const largestElement = findLargestVisibleElement(container);
      const id = largestElement.getAttribute('id');
      if(id) {
        this.updateHeader(id);
        this.renderMonthColor();
      }
    }));
  }
}

export default Calendar;
